﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.Unity;
using System.Diagnostics;
using System.Xml;
using System.Xml.Schema;
using System.IO;
using System.Xml.Linq;
using System.Xml;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;

namespace Infrastructure.Aspect.Services.XmlDataQueries
{
    public class XmlDataQueriesService : IXmlDataQueriesService
    {
        [Dependency]
        public IUnityContainer Container { get; set; }


        private bool HasDefinition(string procname, out string Schema, out string Transform, out bool Encrypt)
        {
            var result = false;
            Schema = null;
            Transform = null;
            Encrypt = false;
            Database db = Container.Resolve<Database>();
            var cmd = db.GetSqlStringCommand("select count(*)  from XmlDataQueries where  queryName = @queryName");
            db.AddInParameter(cmd, "queryName",  System.Data.DbType.String,   procname);            
            var IsDefined  = db.ExecuteScalar(cmd);            
            if ((int)IsDefined > 0)
            {
                var cmdReader = db.GetSqlStringCommand("select querySchema, queryTransform, Encrypt from XmlDataQueries where  queryName = @queryName");
                db.AddInParameter(cmdReader, "queryName", System.Data.DbType.String, procname);            
                var Reader = db.ExecuteReader(cmdReader);
                if (Reader.Read())
                {
                    if (! Reader.IsDBNull(0)) Schema = Reader.GetString(0);
                    if (!Reader.IsDBNull(1)) Transform = Reader.GetString(1);
                    if (!Reader.IsDBNull(2)) Encrypt = Reader.GetBoolean(2);
                }
                Reader.Close();                
            }          
            return result; 
        }
        public string executeprocedure(string procname,  params object[]  parameters)
        {
            string result = null; 
            Database db = Container.Resolve<Database>();                                 
            var reader = db.ExecuteReader(procname, parameters);
            if (reader.Read())
                result = reader.GetString(0);            
            string Schema = null;
            string Transform = null;
            bool Encrypt = false;
            //if (result != null && !this.HasDefinition(procname, out Schema, out Transform, out Encrypt))
            //{
            //    if (!string.IsNullOrEmpty(Schema))
            //    {
            //        XmlSchemaSet schemas = new XmlSchemaSet();
            //        schemas.Add("", XmlReader.Create(new StringReader(Schema)));
            //        bool IsValid = true;
            //        StringBuilder ValidErrors = new StringBuilder();
            //        var xDoc = XDocument.Parse(result);
            //        xDoc.Validate(schemas, (o, e) => { IsValid = false; ValidErrors.AppendLine(e.Message); });
            //        if (!IsValid)
            //        {
            //            throw new XmlSchemaException(ValidErrors.ToString());
            //        }

            //    }
            //    else if (Encrypt)
            //    {
            //        //RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider();


            //        //result = EncryptDocument(result, "shared-key", rsaKey);
            //        //result = DecryptDocument(result, "shared-key", rsaKey);
            //    }
            //}   
            return result;
        }
        public string DecryptDocument(string input, string KeyName, RSA rsaKey)
        {
            XmlDocument XmlDoc = new System.Xml.XmlDocument();
            XmlDoc.LoadXml(input);
            EncryptedXml exml = new EncryptedXml(XmlDoc);
            exml.AddKeyNameMapping(KeyName, rsaKey);            
            exml.DecryptDocument();
            return XmlDoc.InnerXml;
        }
        public string EncryptDocument(string input, string KeyName, RSA rsaKey)
        {            
            RijndaelManaged sessionKey = null;
            string Result = null; 
            try
            {
                XmlDocument XmlDoc = new System.Xml.XmlDocument();
                XmlDoc.LoadXml(input);
                sessionKey = new RijndaelManaged();
                sessionKey.KeySize = 256;
                EncryptedXml eXml = new EncryptedXml(XmlDoc);
                
                //creacion clave
                EncryptedKey ek = new EncryptedKey();
                byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, rsaKey, false);
                ek.CipherData = new CipherData(encryptedKey);
                ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
                KeyInfoName kin = new KeyInfoName();
                kin.Value = KeyName;
                ek.KeyInfo.AddClause(kin);
                eXml.AddKeyNameMapping(KeyName, rsaKey);


                byte[] encryptedElement = eXml.EncryptData(XmlDoc.DocumentElement, sessionKey, true);
                EncryptedData ed = new EncryptedData();
                ed.CipherData = new CipherData(encryptedElement);
                ed.Type = EncryptedXml.XmlEncElementUrl;
                ed.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
                ed.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
                EncryptedXml.ReplaceElement(XmlDoc.DocumentElement, ed, true);
                Result = XmlDoc.InnerXml;
            }
            catch (Exception e)
            {                
                throw e;
            }
            finally
            {
                if (sessionKey != null)
                {
                    sessionKey.Clear();
                }
            }
            return Result;
        }
    }
}
